#pragma once
#include "sem.hpp"
#include <iostream>
#include <vector>
#include <pthread.h>

#define RQSIZE 5 // 队列大小

template <class T>
class RingQueue
{
public:
    RingQueue(int RQsize = RQSIZE)
        : _size(RQsize),
          _rq(RQsize),
          _pStep(0),
          _cStep(0),
          _pSem(RQsize),
          _cSem(0)
    {
        pthread_mutex_init(&_pMtx, nullptr);
        pthread_mutex_init(&_cMtx, nullptr);
    }

    void push(const T &task) // 插入任务
    {
        // 申请信号量
        _pSem.P();
        // 申请互斥锁
        pthread_mutex_lock(&_pMtx);
        // 队列插入任务
        _rq[_pStep++] = task;
        _pStep %= _size;
        // 释放互斥锁
        pthread_mutex_unlock(&_pMtx);
        // 释放信号量
        _cSem.V();
    }

    void pop(T *task) // 获取任务
    {
        // 申请信号量
        _cSem.P();
        // 申请互斥锁
        pthread_mutex_lock(&_cMtx);
        // 队列插入任务
        *task = _rq[_cStep++];
        _cStep %= _size;
        // 释放互斥锁
        pthread_mutex_unlock(&_cMtx);
        // 释放信号量
        _pSem.V();
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&_pMtx);
        pthread_mutex_destroy(&_cMtx);
    }

private:
    int _size;             // 队列大小
    std::vector<T> _rq;    // 队列
    int _pStep;            // 生产者位置
    int _cStep;            // 消费者位置
    Sem _pSem;             // 生产者信号量
    Sem _cSem;             // 消费者信号量
    pthread_mutex_t _pMtx; // 生产者互斥锁
    pthread_mutex_t _cMtx; // 消费者互斥锁
};